String clazzTpl({package}) => """
import 'dart:io';
import 'dart:math';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';

class SysErrorUtil {
  static bool _writeFile(Map<String, String> map) {
    File(map['path']!)
      ..createSync(recursive: true)
      ..writeAsString(map['content']!, flush: true);
    return true;
  }

  static Future<bool> _writeErrorLog(String path, String content) async {
    return compute(_writeFile, {'path': path, 'content': content});
  }

  static void writeErrorLog(Object error, StackTrace stackTrace) async {
    StringBuffer sb = StringBuffer();
    sb.writeln('Error========================');
    sb.writeln(error.toString());
    sb.writeln('\\n\\nStackTrace===================');
    sb.writeln(stackTrace.toString());
    String appDir = (await getApplicationDocumentsDirectory()).path;
    final now = DateTime.now();
    String dateDir = ['\${now.year}年', '\${now.month}月', '\${now.day}日']
        .join(Platform.pathSeparator);
    String fileName =
        '\${now.hour}时\${now.minute}分\${now.second}秒\${now.microsecond}.log';
    await _writeErrorLog(
        '\$appDir\${Platform.pathSeparator}\$dateDir\${Platform.pathSeparator}\$fileName',
        sb.toString());
  }

  static void onError(FlutterErrorDetails details) async {
    Zone.current.handleUncaughtError(details.exception, details.stack!);
  }

  static Widget builder(FlutterErrorDetails details) {
    List<String> errorList = [
      'Error========================',
      details.exceptionAsString(),
      '\\n\\nStackTrace===================',
    ];
    if (details.stack != null) {
      errorList.addAll(details.stack.toString().split('\\n'));
    }
    return Scaffold(
      backgroundColor: Color(0xff3c3f41),
      appBar: AppBar(
        brightness: Brightness.dark,
        title: Text(
          'error',
          style: TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.bold,
          ),
        ),
        backgroundColor: Color(0xff3c3f41),
      ),
      body: CustomScrollView(
        slivers: [
          SliverPersistentHeader(
            pinned: true,
            floating: false,
            delegate: _SliverAppBarDelegate(
              minHeight: 50,
              maxHeight: 100,
              child: LayoutBuilder(builder: (context, constraints) {
                return Container(
                  color: Color(0xff3c3f41),
                  child: Icon(
                    Icons.error,
                    color: Colors.red,
                    size: constraints.biggest.height,
                  ),
                );
              }),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  padding: EdgeInsets.all(8),
                  color: index % 2 == 0 ? Colors.transparent : Colors.white24,
                  child: Text(
                    errorList[index],
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 16,
                    ),
                  ),
                );
              },
              childCount: errorList.length,
            ),
          ),
        ],
      ),
    );
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate({
    required this.minHeight,
    required this.maxHeight,
    required this.child,
  });

  final double minHeight;
  final double maxHeight;
  final Widget child;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return SizedBox.expand(child: child);
  }

  @override
  double get maxExtent => max(maxHeight, minHeight);

  @override
  double get minExtent => minHeight;

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
    return this != oldDelegate;
  }
}
""";
